<template>
  <transition @after-leave="handleAfterLeave">
    <div class="mp-micro" v-show="visible" @click.stop="">
      <div class="qo-preview">
        <div class="qo-preview__header">
          <span class="qo-preview--left">文件预览</span>
          <span class="qo-preview--right" @click="close">关闭</span>
        </div>
        <div class="qo-preview__main">
          <transition name="el-message-fade">
            <div class="qo-main--left" v-show="collapse">
              <div
                class="qo-main--left-img"
                :class="{ 'qo-main--left-border': item.url === showImg.url }"
                v-for="item in list"
                :key="item.url"
                @click="switchImg(item)"
              >
                <span class="text ellipsis">
                  {{ item.name }}
                </span>
              </div>
            </div>
          </transition>
          <!-- <div v-loading="pdfLoading" class="qo-main--right"> -->
          <div class="qo-main--right">
            <!-- img图片格式预览 -->
            <img
              v-if="showImg.type === 'img'"
              :style="imgStyle"
              @mousewheel="mouseWheelHandler"
              ref="img"
              :src="showImg.url"
              @load="handleImgLoad"
              @error="handleImgError"
              @mousedown="handleMouseDown"
              alt=""
            />
            <!-- pdf格式预览 使用vue-pdf -->
            <PafCom
              v-else-if="showImg.type === 'pdf'"
              :style="imgStyle"
              :rotate="rotate"
              :currentPage="currentPage"
              :url="showImg.url"
              style="width: 100%; height: 100%; overflow: auto; background: #00000008"
              @onScrollPage="(page) => (currentPage = scrollPage = page)"
              @onAllPpages="(pages) => (allPage = pages)"
              @onLoadSuccess="(load) => (pdfLoading = load)"
            />
            <!-- office格式 使用微软在线预览 -->
            <iframe
              v-else-if="officePreviewList.includes(showImg.type)"
              style="width: 100%; min-height: 600px"
              :src="`https://view.officeapps.live.com/op/view.aspx?src=${encodeURIComponent(showImg.url)}`"
              width="100%"
              height="100%"
              frameborder="1"
            ></iframe>
            <!-- 音频、视频 -->
            <media-preview
              v-else-if="mediaPreviewList.includes(showImg.type)"
              :viewFileUrl="showImg.url"
              :viewType="showImg.type"
              :style="imgStyle"
              :key="showImg.url"
            ></media-preview>
            <!-- 音频、视频 -->
            <code-preview
              v-else-if="codePreviewList.includes(showImg.type)"
              :viewFileUrl="showImg.url"
              :style="imgStyle"
              :key="showImg.url + 'a'"
            ></code-preview>
            <!-- 其余展示图片 -->
            <extra-preview v-else :style="imgStyle" :previewType="showImg.suffix"></extra-preview>
            <div class="qo-main--right-tool__left" @click="prev">
              <i class="MC_iconfont MC_icon-fangxiang-zuo-xian"></i>
            </div>
            <div class="qo-main--right-tool__right" @click="next">
              <i class="MC_iconfont MC_icon-fangxiang-you-xian"></i>
            </div>
            <div class="qo-main--right-tool">
              <div class="qo-main--side">
                <i
                  :class="collapse ? 'MC_iconfont MC_icon-shouqi-shouqi' : 'MC_iconfont MC_icon-zhankai'"
                  class="iconfont"
                  @click="collapse = !collapse"
                ></i>
              </div>
              <div v-show="showImg.type === 'pdf'" class="qo-main--page">
                <span @click="handleActions('pageDown')">
                  <i class="iconfont iconfangxiang-qian-xian"></i>
                </span>
                <span>{{ scrollPage || currentPage }}/{{ allPage }}</span
                ><span @click="handleActions('pageUp')">
                  <i class="iconfangxiang-hou-xian iconfont"></i>
                </span>
              </div>
              <div class="qo-main--zoom">
                <span @click="handleActions('zoomOut')">
                  <i class="MC_iconfont MC_icon-suofangqi-suoxiao-xian"></i>
                </span>
                <span style="margin: 0 10px">{{ getScale }}%</span
                ><span @click="handleActions('zoomIn')">
                  <i class="MC_iconfont MC_icon-suofangqi-fangda-xian"></i>
                </span>
              </div>
              <div class="qo-main--rotate" @click="handleActions('clocelise')">
                <i class="MC_iconfont MC_icon-shuaxin"></i>
              </div>
              <div class="qo-main--download">
                <a
                  class="MC_iconfont MC_icon-shangchuan-xiazai pointer"
                  style="color: #fff"
                  :href="showImg.url + '?attname=' + showImg.fileName"
                  download
                  target="_blank"
                ></a>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </transition>
</template>
<script lang="ts">
import { defineComponent, reactive, watch, nextTick, computed, toRefs, getCurrentInstance, onBeforeMount } from 'vue'
import PafCom from './pdf.vue'
import ExtraPreview from './ExtraPreview.vue'
import MediaPreview from './MediaPreview.vue'
import CodePreview from './CodePreview.vue'
export default defineComponent({
  name: 'ImagePreview',
  components: {
    PafCom,
    ExtraPreview,
    MediaPreview,
    CodePreview
  },
  props: {
    list: {
      type: Array,
      default: () => []
    },
    img: {
      type: Object,
      default: () => ({})
    }
  },
  setup(props) {
    const instance: any = getCurrentInstance()
    const state = reactive({
      visible: true,
      collapse: true, // 控制左侧显示或隐藏
      currentPage: 1, // pdf当前页
      rotate: 0, // pdf旋转交付
      scrollPage: 0,
      allPage: 1, // pdf总页数
      pdfLoading: false,
      showImg: {} as any,
      officePreviewList: ['doc', 'docx', 'ppt', 'pptx', 'xls', 'xlsx'], // 可以通过office在线预览的后缀列表
      mediaPreviewList: ['video', 'audio'],
      codePreviewList: ['json', 'txt', 'md'], // 可以使用编辑器在线预览的类型
      dragHandler: '' as any,
      transform: {
        scale: 1,
        deg: 0,
        offsetX: 0,
        offsetY: 0,
        enableTransition: false
      },
      loading: false
    })

    const imgStyle = computed(() => {
      const { scale, deg, offsetX, offsetY, enableTransition } = state.transform
      const style = {
        transform: `scale(${scale}) rotate(${deg}deg)`,
        transition: enableTransition ? 'transform .3s' : '',
        marginLeft: `${offsetX}px`,
        marginTop: `${offsetY}px`
      }
      return style
    })

    watch(
      () => state.showImg.url,
      () => {
        nextTick(() => {
          const $img: any = instance?.refs.img
          if ($img && !$img.complete) {
            state.loading = true
          }
        })
      }
    )

    const rafThrottle = (fn: any) => {
      let locked = false
      return function (this: any, ...args: any) {
        if (locked) {
          return false
        }
        locked = true
        window.requestAnimationFrame(() => {
          fn.apply(this, args)
          locked = false
        })
      }
    }

    const mouseWheelHandler = rafThrottle((e: any) => {
      const delta = e.wheelDelta ? e.wheelDelta : -e.detail
      if (delta > 0) {
        handleActions('zoomIn', {
          zoomRate: 0.015,
          enableTransition: false
        })
      } else {
        handleActions('zoomOut', {
          zoomRate: 0.015,
          enableTransition: false
        })
      }
    })

    const getScale = computed(() => {
      return Math.floor(state.transform.scale * 100)
    })

    const close = () => {
      state.visible = false
    }

    onBeforeMount(() => {
      state.showImg = props.img
    })

    const switchImg = (item: any) => {
      resetStyle()
      state.showImg = item
    }

    const resetStyle = () => {
      state.pdfLoading = false
      state.transform = {
        scale: 1,
        deg: 0,
        offsetX: 0,
        offsetY: 0,
        enableTransition: false
      }
      state.scrollPage = 0
      state.currentPage = 1
      state.rotate = 0
    }

    const handleActions = (action: any, options = {}) => {
      const { zoomRate, rotateDeg, enableTransition } = {
        zoomRate: 0.2,
        rotateDeg: 90,
        enableTransition: true,
        ...options
      }
      const { transform } = state
      switch (action) {
        case 'zoomOut':
          if (transform.scale > 0.2) {
            transform.scale = parseFloat((transform.scale - zoomRate).toFixed(3))
          }
          break
        case 'zoomIn':
          transform.scale = parseFloat((transform.scale + zoomRate).toFixed(3))
          break
        case 'clocelise':
          if (state.showImg.type === 'pdf') {
            state.rotate += rotateDeg
          } else {
            transform.deg += rotateDeg
          }
          break
        case 'anticlocelise':
          transform.deg -= rotateDeg
          break
        case 'pageDown':
          state.scrollPage = 0
          if (state.currentPage > 1) {
            state.currentPage--
          }
          break
        case 'pageUp':
          state.scrollPage = 0
          if (state.currentPage < state.allPage) {
            state.currentPage++
          }
          break
      }
      transform.enableTransition = enableTransition
    }

    const handleImgLoad = () => {
      state.loading = false
    }

    const handleImgError = (e: any) => {
      state.loading = false
      e.target.alt = '加载失败'
    }

    const handleMouseDown = (e: any) => {
      if (state.loading || e.button !== 0) {
        return
      }
      const { offsetX, offsetY } = state.transform
      const startX = e.pageX
      const startY = e.pageY
      state.dragHandler = rafThrottle((ev: any) => {
        state.transform.offsetX = offsetX + ev.pageX - startX
        state.transform.offsetY = offsetY + ev.pageY - startY
      })
      document.addEventListener('mousemove', state.dragHandler, false)
      document.addEventListener(
        'mouseup',
        () => {
          document.removeEventListener('mousemove', state.dragHandler, false)
        },
        false
      )
      e.preventDefault()
    }

    const prev = () => {
      findImg((index: any, len: any) => {
        return index === 0 ? len - 1 : index - 1
      })
    }

    const next = () => {
      findImg((index: any, len: any) => {
        return index === len - 1 ? 0 : index + 1
      })
    }

    const findImg = (fn: any) => {
      const len = props.list.length
      props.list.find((item: any, index: any) => {
        if (item.url === state.showImg.url) {
          state.showImg = props.list[fn(index, len)]
          resetStyle()
          return true
        }
      })
    }

    const handleAfterLeave = () => {
      instance?.ctx.$el.parentNode.removeChild(instance?.ctx.$el)
    }

    return {
      imgStyle,
      mouseWheelHandler,
      getScale,
      close,
      switchImg,
      resetStyle,
      rafThrottle,
      handleActions,
      handleImgLoad,
      handleImgError,
      handleMouseDown,
      prev,
      next,
      findImg,
      handleAfterLeave,
      ...toRefs(state)
    }
  }
})
</script>
<style lang="stylus" scoped>
a
  text-decoration none
.qo-preview {
	position fixed
	width 100%
	height 100%
	background #FFFFFF
	top 0
	left 0
	z-index 30000
	&__header {
		background #FFFFFF
		box-shadow 0px 4px 8px rgba(0, 0, 0, 0.05)
		padding 10px 24px
		display flex
		.qo-preview--left {
			font-size 20px
			line-height 36px
			color #000000
			opacity 0.8
			flex 1
		}
		.qo-preview--right {
			flex-basis 80px
			text-align center
			border 1px solid rgba(0, 0, 0, 0.1)
			border-radius 4px
			font-size 14px
			line-height 20px
			padding 8px 0
			cursor pointer
			color rgba(0, 0, 0, 0.8)
			&:hover {
				border-color #3a8ee6
			}
		}
	}
	&__main {
		display flex
		height calc(100% - 58px)
		.qo-main--left {
			width 256px
			background rgba(0, 0, 0, 0.03)
			height 100%
			overflow-y auto
			padding 16px
			&-img {
				background #FFFFFF
				border-radius 4px
				padding 8px 10px
				margin-bottom 16px
				font-weight 500
				font-size 14px
				line-height 20px
				color #000000
				opacity 0.8
				cursor pointer
				display flex
				.icon {
					flex-basis 35px
				}
				.text {
					flex 1
					line-height 25px
				}
			}
			&-border {
				border 1px solid var(--mc-main-color)
			}
		}
		.qo-main--right {
			flex 1
			position relative
			text-align center
			position relative
			display flex /* Flex布局 */
			display -webkit-flex /* Safari */
			justify-content center
			align-items center /* 指定垂直居中 */
			img {
				max-width 100%
				max-height 100%
			}
			&-tool {
				position absolute
				bottom 40px
				left 50%
				margin-left -161px
				padding 8px 18px
				background rgba(0, 0, 0, 0.8)
				box-shadow 0px 0px 8px rgba(0, 0, 0, 0.05)
				border-radius 32px
				color #fff
				display flex
				.qo-main--side {
					border-right 1px solid rgba(255, 255, 255, 0.3)
					padding-right 18px
				}
				.qo-main--page {
					padding 0 0 0 25px
					.iconfangxiang-qian-xian {
						padding-right 9px
					}
					.iconfangxiang-hou-xian {
						padding-left 9px
					}
				}
				.qo-main--zoom {
					padding 0 35px 0 25px
					.el-icon-zoom-out {
						padding-right 9px
					}
					.el-icon-zoom-in {
						padding-left 9px
					}
				}
				.qo-main--rotate {
					border-right 1px solid rgba(255, 255, 255, 0.3)
					padding-right 26px
				}
				.qo-main--download {
					padding-left 18px
				}
				.qo-main--delete {
				}
			}
			&-tool__left {
				position absolute
				cursor pointer
				left 32px
				top 50%
				width 48px
				height 48px
				text-align center
				line-height 48px
				margin-top -24px
				background #FFFFFF
				box-shadow 0px 0px 8px rgba(0, 0, 0, 0.1)
				border-radius 88px
				.MC_iconfont {
					color #000000
					opacity 0.6
				}
			}
			&-tool__left:hover {
				.MC_iconfont {
					color #000000
					opacity 0.8
				}
			}
			&-tool__right {
				position absolute
				cursor pointer
				right 32px
				width 48px
				height 48px
				top 50%
				text-align center
				line-height 48px
				margin-top -24px
				background #FFFFFF
				box-shadow 0px 0px 8px rgba(0, 0, 0, 0.1)
				border-radius 88px
				.MC_iconfont {
					color #000000
					opacity 0.6
				}
			}
			&-tool__right:hover {
				.MC_iconfont {
					color #000000
					opacity 0.8
				}
			}
		}
	}
}
.fade-enter-active, .fade-leave-active {
	transition all 6s ease
}
.fade-enter, .fade-leave-to { /* .fade-leave-active below version 2.1.8 */
	opacity 0
}
.iconfont {
	cursor pointer
}
</style>
